{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 迭代器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 可迭代对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'str'>\n",
      "1,2,3, \n",
      "<class 'list'>\n",
      "1,2,3, \n",
      "<class 'tuple'>\n",
      "1,2,3, \n",
      "<class 'dict'>\n",
      "1,2,3, \n",
      "<class 'set'>\n",
      "1,2,3, \n"
     ]
    }
   ],
   "source": [
    "iterables = [\n",
    "    \"123\",                  # string\n",
    "    [1,2,3],                # list\n",
    "    (1,2,3),                # tuple\n",
    "    {1:\"a\", 2:\"b\", 3:\"c\"},  # dictionary keys  \n",
    "    {1,2,3},                # set\n",
    "]\n",
    "\n",
    "for iterable in iterables:\n",
    "    print(type(iterable))\n",
    "\n",
    "    for item in iterable:\n",
    "        print(item, end=',')\n",
    "    \n",
    "    print(' ')  # Blank line for better readability between different iterables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 可迭代对象的接口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def common_attrs(*objs):\n",
    "    \"\"\"Return a set of common attributes of all objects in objs.\"\"\"\n",
    "    if not objs:\n",
    "        return set()\n",
    "    \n",
    "    common = set(dir(objs[0]))\n",
    "    for obj in objs[1:]:\n",
    "        common &= set(dir(obj))\n",
    "    common -= set(dir(object))  # Remove attributes from the base 'object' class\n",
    "    return common\n",
    "\n",
    "# 内省能力 内置的dir函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Common attributes: {'__len__', '__iter__', '__contains__'}\n"
     ]
    }
   ],
   "source": [
    "iterable_common_attrs = common_attrs(*iterables)\n",
    "\n",
    "print(\"Common attributes:\", iterable_common_attrs)\n",
    "\n",
    "# __contains__, __len__ 容器类型的可迭代对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Common attributes after adding file object: {'__iter__'}\n"
     ]
    }
   ],
   "source": [
    "# 文件对象也是可迭代对象\n",
    "f = open(\"Sec1.ipynb\", \"r\")\n",
    "\n",
    "iterables.append(f)\n",
    "\n",
    "iterable_common_attrs = common_attrs(*iterables)\n",
    "print(\"Common attributes after adding file object:\", iterable_common_attrs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<str_iterator object at 0x000001C647663190>\n",
      "<list_iterator object at 0x000001C647663190>\n",
      "<tuple_iterator object at 0x000001C647663190>\n",
      "<dict_keyiterator object at 0x000001C647023A10>\n",
      "<set_iterator object at 0x000001C6476AB7C0>\n",
      "<_io.TextIOWrapper name='Sec1.ipynb' mode='r' encoding='UTF-8'>\n"
     ]
    }
   ],
   "source": [
    "# 双下划线内置函数\n",
    "\n",
    "# __iter__  -> 内置函数 iter()\n",
    "\n",
    "for iterable in iterables:\n",
    "    print(iter(iterable))  # 返回一个迭代器对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 迭代器的接口"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Common attributes of iterators: {'__iter__', '__next__'}\n"
     ]
    }
   ],
   "source": [
    "iterators = [iter(it) for it in iterables]\n",
    "\n",
    "iterator_common_attrs = common_attrs(*iterators)\n",
    "\n",
    "print(\"Common attributes of iterators:\", iterator_common_attrs)\n",
    "# 迭代器有两个接口： __iter__, __next__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 迭代器的用法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "actions = [\"wakeup\", \"brush\", \"wash\", \"eat\", \"sleep\"] # 构建一个可迭代对象\n",
    "\n",
    "action_iter = iter(actions) # 通过可迭代对象的__iter__方法，获取迭代器对象"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "wakeup\n",
      "brush\n",
      "wash\n",
      "eat\n",
      "sleep\n"
     ]
    }
   ],
   "source": [
    "# 迭代器的遍历\n",
    "while True:\n",
    "    try:\n",
    "        action = next(action_iter) # 通过迭代器的__next__方法，获取下一个对象\n",
    "        print(action)\n",
    "    except StopIteration:  # 捕获迭代器结束的异常\n",
    "        break\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 自定义迭代器\n",
    "- 基本功能：\n",
    "    - 初始化时要传入可迭代对象  \n",
    "    - 要初始化迭代进度  \n",
    "    - 每次迭代时，即每次调用__next__方法时：\n",
    "        - 如果仍有元素可供迭代，则返回本轮迭代的对象，同时更新当前迭代进度；  \n",
    "        - 如果没有元素用来返回，则迭代结束，抛出StopIteration异常。\n",
    "\n",
    "- 额外：\n",
    "    - 设置黑名单，如果当前元素在黑名单，则跳过；  \n",
    "    - 将符合条件的元素*2后返回。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "wakeup\n",
      "brush\n",
      "wash\n",
      "eat\n",
      "sleep\n"
     ]
    }
   ],
   "source": [
    "BLACK_list = ['kill', 'shot']\n",
    "\n",
    "class SelfDefineIter:\n",
    "    def __init__(self, actions):\n",
    "        self.actions = actions\n",
    "        self.index = 0  # 记录当前迭代到的位置\n",
    "    \n",
    "    def __next__(self):\n",
    "        while self.index < len(self.actions):\n",
    "            action = self.actions[self.index]\n",
    "            self.index += 1\n",
    "            if action in BLACK_list:\n",
    "                continue  # 跳过黑名单中的动作\n",
    "            return action\n",
    "        raise StopIteration  # 如果没有更多元素，抛出StopIteration异常\n",
    "\n",
    "actions = [\"wakeup\", \"brush\", \"wash\", \"eat\", \"sleep\", \"kill\", \"shot\"]\n",
    "custom_iter = SelfDefineIter(actions)\n",
    "while True:\n",
    "    try:\n",
    "        action = next(custom_iter)\n",
    "        print(action)\n",
    "    except StopIteration:\n",
    "        break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'SelfDefineIter' object is not iterable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[12], line 2\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[38;5;66;03m# for 循环需要的是【可迭代对象】，而不是【迭代器对象】\u001b[39;00m\n\u001b[1;32m----> 2\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m custom_iter:  \u001b[38;5;66;03m# 迭代器对象也可以直接用于for循环\u001b[39;00m\n\u001b[0;32m      3\u001b[0m     \u001b[38;5;28mprint\u001b[39m(x)\n",
      "\u001b[1;31mTypeError\u001b[0m: 'SelfDefineIter' object is not iterable"
     ]
    }
   ],
   "source": [
    "# for 循环需要的是【可迭代对象】，而不是【迭代器对象】\n",
    "for x in custom_iter:  # 迭代器对象也可以直接用于for循环\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "wakeup\n",
      "brush\n",
      "wash\n",
      "eat\n",
      "sleep\n"
     ]
    }
   ],
   "source": [
    "BLACK_list = ['kill', 'shot']\n",
    "\n",
    "class SelfDefineIter:\n",
    "    def __init__(self, actions):\n",
    "        self.actions = actions\n",
    "        self.index = 0  # 记录当前迭代到的位置\n",
    "    \n",
    "    def __next__(self):\n",
    "        while self.index < len(self.actions):\n",
    "            action = self.actions[self.index]\n",
    "            self.index += 1\n",
    "            if action in BLACK_list:\n",
    "                continue  # 跳过黑名单中的动作\n",
    "            return action\n",
    "        raise StopIteration  # 如果没有更多元素，抛出StopIteration异常\n",
    "    \n",
    "    def __iter__(self):  # 返回迭代器对象本身\n",
    "        return self\n",
    "\n",
    "actions = [\"wakeup\", \"brush\", \"wash\", \"eat\", \"sleep\", \"kill\", \"shot\"]\n",
    "custom_iter = SelfDefineIter(actions)\n",
    "\n",
    "for x in custom_iter:\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 迭代器协议\n",
    "- 迭代器必须同时实现__next__和__iter__两个方法  \n",
    "- 迭代器必须是可迭代的，即一种可迭代对象\n",
    "- 所有迭代器的__iter__方法只需 return self即可\n",
    "- 统一通过__next__()方法获取数据，可以屏蔽底层数据的不同读取方式，简化编程。  \n",
    "##### 可迭代对象\n",
    "- 容器类型\n",
    "    - 列表、元组、字典\n",
    "    - 只有__iter__接口\n",
    "    - 静态数据\n",
    "    - 需要额外的迭代器支持\n",
    "    - 支持多次迭代\n",
    "\n",
    "- 迭代器类型\n",
    "    - 文件、StringIO等\n",
    "    - 同时实现__iter__、__next__接口\n",
    "    - 动态数据\n",
    "    - 只能一次迭代，单向\n",
    "\n",
    "-   So\n",
    "    - 一个可迭代对象可以构建多个迭代器  \n",
    "    - 一种迭代器可以应用与任意多个可迭代对象（包括本身）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对于容器类型的可迭代对象，此时迭代器在幕后被创建，生命周期仅在for循环内\n",
    "for iterable in iterables:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对于迭代器对象，迭代器与for循环分离，迭代器的生命周期不受for循环控制\n",
    "iterables = [1,2,3]\n",
    "iterors = iter(iterables)\n",
    "for x in iterors:\n",
    "    pass\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 应用场景\n",
    "- 数据管道\n",
    "    - 可以任意的嵌套连接\n",
    "    - [for loop] <- [iteror] <- [iteror] <- ... <- [iteror] <- [iterable]\n",
    "    - 很多个迭代器串联，形成数据数据的管道，即**数据流**\n",
    "    - 在这个管道中，每一次只通过一份数据，避免了一次性加载所有数据  \n",
    "    - 迭代器不仅仅是开始按顺序返回数据，开始进行**数据处理**的工作 \n",
    "    - 通过迭代器获取，远离了数据存储。  \n",
    "\n",
    "- 数据生成器\n",
    "    - 实时生成数据，不考虑数据存储"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from random import random\n",
    "\n",
    "class RandomIterator:\n",
    "    def __init__(self):\n",
    "        return self\n",
    "\n",
    "    def __next__(self):\n",
    "        return random()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 附录\n",
    "- 并不是所有的可迭代对象都必须有__iter__方法。\n",
    "- 如果一个对象没有__iter__方法，但是定义了__getitem__方法，同样是可以迭代的。\n",
    "- 因此，不能通过检查__iter__方法来判断一个对象是否是可迭代的，而是应该直接使用iter()函数，如果不可迭代，则会抛出TypeError异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "2\n",
      "4\n",
      "6\n",
      "8\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "class DumbList:\n",
    "    def __getitem__(self, index):\n",
    "        if index < 0:\n",
    "            return StopIteration\n",
    "        return index * 2\n",
    "    \n",
    "dl = DumbList()\n",
    "for item in dl:\n",
    "    print(item)\n",
    "    if item >= 10:\n",
    "        break"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
